// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/renderer_host/render_widget_host_view_aura.h"

#include <set>
#include <utility>

#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "cc/layers/layer.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
#include "cc/resources/texture_mailbox.h"
#include "cc/trees/layer_tree_settings.h"
#include "components/display_compositor/gl_helper.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_state_impl.h"
#include "content/browser/bad_message.h"
#include "content/browser/frame_host/frame_tree.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/renderer_host/delegated_frame_host_client_aura.h"
#include "content/browser/renderer_host/dip_util.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target_aura.h"
#include "content/browser/renderer_host/input/touch_selection_controller_client_aura.h"
#include "content/browser/renderer_host/overscroll_controller.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_view_host_delegate_view.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
#include "content/browser/renderer_host/render_widget_host_view_event_handler.h"
#include "content/browser/renderer_host/ui_events_helper.h"
#include "content/common/content_switches_internal.h"
#include "content/common/input_messages.h"
#include "content/common/render_widget_window_tree_client_factory.mojom.h"
#include "content/common/site_isolation_policy.h"
#include "content/common/text_input_state.h"
#include "content/common/view_messages.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/overscroll_configuration.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/common/child_process_host.h"
#include "content/public/common/content_switches.h"
#include "gpu/ipc/common/gpu_messages.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "services/ui/public/interfaces/window_manager_constants.mojom.h"
#include "third_party/WebKit/public/platform/WebInputEvent.h"
#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/cursor_client_observer.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/client/transient_window_client.h"
#include "ui/aura/client/window_parenting_client.h"
#include "ui/aura/env.h"
#include "ui/aura/mus/window_port_mus.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/hit_test.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ui_base_types.h"
#include "ui/compositor/compositor_vsync_manager.h"
#include "ui/compositor/dip_util.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/events/blink/blink_event_util.h"
#include "ui/events/blink/web_input_event.h"
#include "ui/events/event.h"
#include "ui/events/event_utils.h"
#include "ui/events/gesture_detection/gesture_configuration.h"
#include "ui/events/gestures/gesture_recognizer.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/skia_util.h"
#include "ui/touch_selection/touch_selection_controller.h"
#include "ui/wm/public/activation_client.h"
#include "ui/wm/public/scoped_tooltip_disabler.h"
#include "ui/wm/public/tooltip_client.h"

#if defined(OS_WIN)
#include "base/time/time.h"
#include "content/browser/accessibility/browser_accessibility_manager_win.h"
#include "content/browser/accessibility/browser_accessibility_win.h"
#include "content/browser/renderer_host/legacy_render_widget_host_win.h"
#include "ui/base/win/hidden_window.h"
#include "ui/base/win/osk_display_manager.h"
#include "ui/base/win/osk_display_observer.h"
#include "ui/display/win/screen_win.h"
#include "ui/gfx/gdi_util.h"
#endif

#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
#include "ui/base/ime/linux/text_edit_command_auralinux.h"
#include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h"
#endif

using gfx::RectToSkIRect;
using gfx::SkIRectToRect;

using blink::WebGestureEvent;
using blink::WebInputEvent;
using blink::WebTouchEvent;

namespace content {

namespace {

#if defined(OS_WIN)

    // This class implements the ui::OnScreenKeyboardObserver interface
    // which provides notifications about the on screen keyboard on Windows getting
    // displayed or hidden in response to taps on editable fields.
    // It provides functionality to request blink to scroll the input field if it
    // is obscured by the on screen keyboard.
    class WinScreenKeyboardObserver : public ui::OnScreenKeyboardObserver {
    public:
        WinScreenKeyboardObserver(RenderWidgetHostImpl* host,
            const gfx::Point& location_in_screen,
            float scale_factor,
            aura::Window* window)
            : host_(host)
            , location_in_screen_(location_in_screen)
            , device_scale_factor_(scale_factor)
            , window_(window)
        {
            host_->GetView()->SetInsets(gfx::Insets());
        }

        // base::win::OnScreenKeyboardObserver overrides.
        void OnKeyboardVisible(const gfx::Rect& keyboard_rect_pixels) override
        {
            gfx::Point location_in_pixels = gfx::ConvertPointToPixel(device_scale_factor_, location_in_screen_);

            // Restore the viewport.
            host_->GetView()->SetInsets(gfx::Insets());

            if (keyboard_rect_pixels.Contains(location_in_pixels)) {
                aura::client::ScreenPositionClient* screen_position_client = aura::client::GetScreenPositionClient(window_->GetRootWindow());
                if (!screen_position_client)
                    return;

                DVLOG(1) << "OSK covering focus point.";
                gfx::Rect keyboard_rect = gfx::ConvertRectToDIP(device_scale_factor_, keyboard_rect_pixels);
                gfx::Rect bounds_in_screen = window_->GetBoundsInScreen();

                DCHECK(bounds_in_screen.bottom() > keyboard_rect.y());

                // Set the viewport of the window to be just above the on screen
                // keyboard.
                int viewport_bottom = bounds_in_screen.bottom() - keyboard_rect.y();

                // If the viewport is bigger than the view, then we cannot handle it
                // with the current approach. Moving the window above the OSK is one way.
                // That for a later patchset.
                if (viewport_bottom > bounds_in_screen.height())
                    return;

                host_->GetView()->SetInsets(gfx::Insets(0, 0, viewport_bottom, 0));

                gfx::Point origin(location_in_screen_);
                screen_position_client->ConvertPointFromScreen(window_, &origin);

                // TODO(ekaramad): We should support the case where the focused node is
                // inside an OOPIF (https://crbug.com/676037).
                // We want to scroll the node into a rectangle which originates from
                // the touch point and a small offset (10) in either direction.
                gfx::Rect node_rect(origin.x(), origin.y(), 10, 10);
                host_->ScrollFocusedEditableNodeIntoRect(node_rect);
            }
        }

        void OnKeyboardHidden(const gfx::Rect& keyboard_rect_pixels) override
        {
            // Restore the viewport.
            host_->GetView()->SetInsets(gfx::Insets());
        }

    private:
        RenderWidgetHostImpl* host_;
        // The location in DIPs where the touch occurred.
        gfx::Point location_in_screen_;
        // The current device scale factor.
        float device_scale_factor_;

        // The content Window.
        aura::Window* window_;

        DISALLOW_COPY_AND_ASSIGN(WinScreenKeyboardObserver);
    };
#endif // defined(OS_WIN)

    // Callback from embedding the renderer.
    void EmbedCallback(bool result)
    {
        if (!result)
            DVLOG(1) << "embed failed";
    }

} // namespace

// We need to watch for mouse events outside a Web Popup or its parent
// and dismiss the popup for certain events.
class RenderWidgetHostViewAura::EventFilterForPopupExit
    : public ui::EventHandler {
public:
    explicit EventFilterForPopupExit(RenderWidgetHostViewAura* rwhva)
        : rwhva_(rwhva)
    {
        DCHECK(rwhva_);
        aura::Env::GetInstance()->AddPreTargetHandler(this);
    }

    ~EventFilterForPopupExit() override
    {
        aura::Env::GetInstance()->RemovePreTargetHandler(this);
    }

    // Overridden from ui::EventHandler
    void OnMouseEvent(ui::MouseEvent* event) override
    {
        rwhva_->ApplyEventFilterForPopupExit(event);
    }

    void OnTouchEvent(ui::TouchEvent* event) override
    {
        rwhva_->ApplyEventFilterForPopupExit(event);
    }

private:
    RenderWidgetHostViewAura* rwhva_;

    DISALLOW_COPY_AND_ASSIGN(EventFilterForPopupExit);
};

void RenderWidgetHostViewAura::ApplyEventFilterForPopupExit(
    ui::LocatedEvent* event)
{
    if (in_shutdown_ || is_fullscreen_ || !event->target())
        return;

    if (event->type() != ui::ET_MOUSE_PRESSED && event->type() != ui::ET_TOUCH_PRESSED) {
        return;
    }

    aura::Window* target = static_cast<aura::Window*>(event->target());
    if (target != window_ && (!popup_parent_host_view_ || target != popup_parent_host_view_->window_)) {
        // If we enter this code path it means that we did not receive any focus
        // lost notifications for the popup window. Ensure that blink is aware
        // of the fact that focus was lost for the host window by sending a Blur
        // notification. We also set a flag in the view indicating that we need
        // to force a Focus notification on the next mouse down.
        if (popup_parent_host_view_ && popup_parent_host_view_->host_) {
            popup_parent_host_view_->event_handler()
                ->set_focus_on_mouse_down_or_key_event(true);
            popup_parent_host_view_->host_->Blur();
        }
        // Note: popup_parent_host_view_ may be NULL when there are multiple
        // popup children per view. See: RenderWidgetHostViewAura::InitAsPopup().
        Shutdown();
    }
}

// We have to implement the WindowObserver interface on a separate object
// because clang doesn't like implementing multiple interfaces that have
// methods with the same name. This object is owned by the
// RenderWidgetHostViewAura.
class RenderWidgetHostViewAura::WindowObserver : public aura::WindowObserver {
public:
    explicit WindowObserver(RenderWidgetHostViewAura* view)
        : view_(view)
    {
        view_->window_->AddObserver(this);
    }

    ~WindowObserver() override { view_->window_->RemoveObserver(this); }

    // Overridden from aura::WindowObserver:
    void OnWindowAddedToRootWindow(aura::Window* window) override
    {
        if (window == view_->window_)
            view_->AddedToRootWindow();
    }

    void OnWindowRemovingFromRootWindow(aura::Window* window,
        aura::Window* new_root) override
    {
        if (window == view_->window_)
            view_->RemovingFromRootWindow();
    }

    void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override
    {
        view_->ParentHierarchyChanged();
    }

private:
    RenderWidgetHostViewAura* view_;

    DISALLOW_COPY_AND_ASSIGN(WindowObserver);
};

// This class provides functionality to observe the ancestors of the RWHVA for
// bounds changes. This is done to snap the RWHVA window to a pixel boundary,
// which could change when the bounds relative to the root changes.
// An example where this happens is below:-
// The fast resize code path for bookmarks where in the parent of RWHVA which
// is WCV has its bounds changed before the bookmark is hidden. This results in
// the traditional bounds change notification for the WCV reporting the old
// bounds as the bookmark is still around. Observing all the ancestors of the
// RWHVA window enables us to know when the bounds of the window relative to
// root changes and allows us to snap accordingly.
class RenderWidgetHostViewAura::WindowAncestorObserver
    : public aura::WindowObserver {
public:
    explicit WindowAncestorObserver(RenderWidgetHostViewAura* view)
        : view_(view)
    {
        aura::Window* parent = view_->window_->parent();
        while (parent) {
            parent->AddObserver(this);
            ancestors_.insert(parent);
            parent = parent->parent();
        }
    }

    ~WindowAncestorObserver() override
    {
        RemoveAncestorObservers();
    }

    void OnWindowBoundsChanged(aura::Window* window,
        const gfx::Rect& old_bounds,
        const gfx::Rect& new_bounds) override
    {
        DCHECK(ancestors_.find(window) != ancestors_.end());
        if (new_bounds.origin() != old_bounds.origin())
            view_->HandleParentBoundsChanged();
    }

private:
    void RemoveAncestorObservers()
    {
        for (auto* ancestor : ancestors_)
            ancestor->RemoveObserver(this);
        ancestors_.clear();
    }

    RenderWidgetHostViewAura* view_;
    std::set<aura::Window*> ancestors_;

    DISALLOW_COPY_AND_ASSIGN(WindowAncestorObserver);
};

bool IsMus()
{
    return aura::Env::GetInstance()->mode() == aura::Env::Mode::MUS && base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseMusInRenderer);
}

////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, public:

RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host,
    bool is_guest_view_hack)
    : host_(RenderWidgetHostImpl::From(host))
    , window_(nullptr)
    , in_shutdown_(false)
    , in_bounds_changed_(false)
    , popup_parent_host_view_(nullptr)
    , popup_child_host_view_(nullptr)
    , is_loading_(false)
    , has_composition_text_(false)
    , begin_frame_source_(nullptr)
    , needs_begin_frames_(false)
    , needs_flush_input_(false)
    , added_frame_observer_(false)
    , cursor_visibility_state_in_renderer_(UNKNOWN)
    ,
#if defined(OS_WIN)
    legacy_render_widget_host_HWND_(nullptr)
    , legacy_window_destroyed_(false)
    , virtual_keyboard_requested_(false)
    ,
#endif
    has_snapped_to_boundary_(false)
    , is_guest_view_hack_(is_guest_view_hack)
    , device_scale_factor_(0.0f)
    , last_active_widget_process_id_(ChildProcessHost::kInvalidUniqueID)
    , last_active_widget_routing_id_(MSG_ROUTING_NONE)
    , event_handler_(new RenderWidgetHostViewEventHandler(host_, this, this))
    , weak_ptr_factory_(this)
{
    if (!is_guest_view_hack_)
        host_->SetView(this);

    // We should start observing the TextInputManager for IME-related events as
    // well as monitoring its lifetime.
    if (GetTextInputManager())
        GetTextInputManager()->AddObserver(this);

    bool overscroll_enabled = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kOverscrollHistoryNavigation) != "0";
    SetOverscrollControllerEnabled(overscroll_enabled);

    selection_controller_client_.reset(
        new TouchSelectionControllerClientAura(this));
    CreateSelectionController();

    RenderViewHost* rvh = RenderViewHost::From(host_);
    if (rvh) {
        // TODO(mostynb): actually use prefs.  Landing this as a separate CL
        // first to rebaseline some unreliable layout tests.
        ignore_result(rvh->GetWebkitPreferences());
    }
}

////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, RenderWidgetHostView implementation:

void RenderWidgetHostViewAura::InitAsChild(
    gfx::NativeView parent_view)
{
    CreateDelegatedFrameHostClient();

    CreateAuraWindow(ui::wm::WINDOW_TYPE_CONTROL);

    if (parent_view)
        parent_view->AddChild(GetNativeView());

    const display::Display display = display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
    device_scale_factor_ = display.device_scale_factor();
}

void RenderWidgetHostViewAura::InitAsPopup(
    RenderWidgetHostView* parent_host_view,
    const gfx::Rect& bounds_in_screen)
{
    CreateDelegatedFrameHostClient();

    popup_parent_host_view_ = static_cast<RenderWidgetHostViewAura*>(parent_host_view);

    // TransientWindowClient may be NULL during tests.
    aura::client::TransientWindowClient* transient_window_client = aura::client::GetTransientWindowClient();
    RenderWidgetHostViewAura* old_child = popup_parent_host_view_->popup_child_host_view_;
    if (old_child) {
        // TODO(jhorwich): Allow multiple popup_child_host_view_ per view, or
        // similar mechanism to ensure a second popup doesn't cause the first one
        // to never get a chance to filter events. See crbug.com/160589.
        DCHECK(old_child->popup_parent_host_view_ == popup_parent_host_view_);
        if (transient_window_client) {
            transient_window_client->RemoveTransientChild(
                popup_parent_host_view_->window_, old_child->window_);
        }
        old_child->popup_parent_host_view_ = NULL;
    }
    popup_parent_host_view_->SetPopupChild(this);
    CreateAuraWindow(ui::wm::WINDOW_TYPE_MENU);

    // Setting the transient child allows for the popup to get mouse events when
    // in a system modal dialog. Do this before calling ParentWindowWithContext
    // below so that the transient parent is visible to WindowTreeClient.
    // This fixes crbug.com/328593.
    if (transient_window_client) {
        transient_window_client->AddTransientChild(
            popup_parent_host_view_->window_, window_);
    }

    aura::Window* root = popup_parent_host_view_->window_->GetRootWindow();
    aura::client::ParentWindowWithContext(window_, root, bounds_in_screen);

    SetBounds(bounds_in_screen);
    Show();
    if (NeedsMouseCapture())
        window_->SetCapture();

    event_filter_for_popup_exit_.reset(new EventFilterForPopupExit(this));

    const display::Display display = display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
    device_scale_factor_ = display.device_scale_factor();
}

void RenderWidgetHostViewAura::InitAsFullscreen(
    RenderWidgetHostView* reference_host_view)
{
    is_fullscreen_ = true;
    CreateDelegatedFrameHostClient();
    CreateAuraWindow(ui::wm::WINDOW_TYPE_NORMAL);
    window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);

    aura::Window* parent = NULL;
    gfx::Rect bounds;
    if (reference_host_view) {
        aura::Window* reference_window = static_cast<RenderWidgetHostViewAura*>(reference_host_view)->window_;
        event_handler_->TrackHost(reference_window);
        display::Display display = display::Screen::GetScreen()->GetDisplayNearestWindow(reference_window);
        parent = reference_window->GetRootWindow();
        bounds = display.bounds();
    }
    aura::client::ParentWindowWithContext(window_, parent, bounds);
    Show();
    Focus();

    const display::Display display = display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
    device_scale_factor_ = display.device_scale_factor();
}

RenderWidgetHost* RenderWidgetHostViewAura::GetRenderWidgetHost() const
{
    return host_;
}

void RenderWidgetHostViewAura::Show()
{
    window_->Show();

    if (!host_->is_hidden())
        return;

    bool has_saved_frame = delegated_frame_host_ ? delegated_frame_host_->HasSavedFrame() : false;
    ui::LatencyInfo renderer_latency_info, browser_latency_info;
    if (has_saved_frame) {
        browser_latency_info.AddLatencyNumber(
            ui::TAB_SHOW_COMPONENT, host_->GetLatencyComponentId(), 0);
    } else {
        renderer_latency_info.AddLatencyNumber(
            ui::TAB_SHOW_COMPONENT, host_->GetLatencyComponentId(), 0);
    }
    host_->WasShown(renderer_latency_info);

    aura::Window* root = window_->GetRootWindow();
    if (root) {
        aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(root);
        if (cursor_client)
            NotifyRendererOfCursorVisibilityState(cursor_client->IsCursorVisible());
    }

    if (delegated_frame_host_)
        delegated_frame_host_->WasShown(browser_latency_info);

#if defined(OS_WIN)
    UpdateLegacyWin();
#endif
}

void RenderWidgetHostViewAura::Hide()
{
    window_->Hide();

    // TODO(wjmaclean): can host_ ever be null?
    if (host_ && !host_->is_hidden()) {
        host_->WasHidden();
        if (delegated_frame_host_)
            delegated_frame_host_->WasHidden();

#if defined(OS_WIN)
        aura::WindowTreeHost* host = window_->GetHost();
        if (host) {
            // We reparent the legacy Chrome_RenderWidgetHostHWND window to the global
            // hidden window on the same lines as Windowed plugin windows.
            if (legacy_render_widget_host_HWND_)
                legacy_render_widget_host_HWND_->UpdateParent(ui::GetHiddenWindow());
        }
#endif
    }

#if defined(OS_WIN)
    if (legacy_render_widget_host_HWND_)
        legacy_render_widget_host_HWND_->Hide();
#endif
}

void RenderWidgetHostViewAura::SetSize(const gfx::Size& size)
{
    // For a SetSize operation, we don't care what coordinate system the origin
    // of the window is in, it's only important to make sure that the origin
    // remains constant after the operation.
    InternalSetBounds(gfx::Rect(window_->bounds().origin(), size));
}

void RenderWidgetHostViewAura::SetBounds(const gfx::Rect& rect)
{
    gfx::Point relative_origin(rect.origin());

    // RenderWidgetHostViewAura::SetBounds() takes screen coordinates, but
    // Window::SetBounds() takes parent coordinates, so do the conversion here.
    aura::Window* root = window_->GetRootWindow();
    if (root) {
        aura::client::ScreenPositionClient* screen_position_client = aura::client::GetScreenPositionClient(root);
        if (screen_position_client) {
            screen_position_client->ConvertPointFromScreen(window_->parent(),
                &relative_origin);
        }
    }

    InternalSetBounds(gfx::Rect(relative_origin, rect.size()));
}

gfx::Vector2dF RenderWidgetHostViewAura::GetLastScrollOffset() const
{
    return last_scroll_offset_;
}

gfx::NativeView RenderWidgetHostViewAura::GetNativeView() const
{
    return window_;
}

#if defined(OS_WIN)
HWND RenderWidgetHostViewAura::GetHostWindowHWND() const
{
    aura::WindowTreeHost* host = window_->GetHost();
    return host ? host->GetAcceleratedWidget() : nullptr;
}
#endif

gfx::NativeViewAccessible RenderWidgetHostViewAura::GetNativeViewAccessible()
{
#if defined(OS_WIN)
    aura::WindowTreeHost* host = window_->GetHost();
    if (!host)
        return static_cast<gfx::NativeViewAccessible>(NULL);
    BrowserAccessibilityManager* manager = host_->GetOrCreateRootBrowserAccessibilityManager();
    if (manager)
        return ToBrowserAccessibilityWin(manager->GetRoot());
#endif

    NOTIMPLEMENTED();
    return static_cast<gfx::NativeViewAccessible>(NULL);
}

ui::TextInputClient* RenderWidgetHostViewAura::GetTextInputClient()
{
    return this;
}

void RenderWidgetHostViewAura::SetNeedsBeginFrames(bool needs_begin_frames)
{
    needs_begin_frames_ = needs_begin_frames;
    UpdateNeedsBeginFramesInternal();
}

void RenderWidgetHostViewAura::OnSetNeedsFlushInput()
{
    needs_flush_input_ = true;
    UpdateNeedsBeginFramesInternal();
}

void RenderWidgetHostViewAura::UpdateNeedsBeginFramesInternal()
{
    if (!begin_frame_source_)
        return;

    bool needs_frame = needs_begin_frames_ || needs_flush_input_;
    if (needs_frame == added_frame_observer_)
        return;

    added_frame_observer_ = needs_frame;
    if (needs_frame)
        begin_frame_source_->AddObserver(this);
    else
        begin_frame_source_->RemoveObserver(this);
}

void RenderWidgetHostViewAura::OnBeginFrame(
    const cc::BeginFrameArgs& args)
{
    needs_flush_input_ = false;
    host_->FlushInput();
    UpdateNeedsBeginFramesInternal();
    host_->Send(new ViewMsg_BeginFrame(host_->GetRoutingID(), args));
    last_begin_frame_args_ = args;
}

const cc::BeginFrameArgs& RenderWidgetHostViewAura::LastUsedBeginFrameArgs()
    const
{
    return last_begin_frame_args_;
}

void RenderWidgetHostViewAura::OnBeginFrameSourcePausedChanged(bool paused)
{
    // Only used on Android WebView.
}

RenderFrameHostImpl* RenderWidgetHostViewAura::GetFocusedFrame()
{
    RenderViewHost* rvh = RenderViewHost::From(host_);
    if (!rvh)
        return nullptr;
    FrameTreeNode* focused_frame = rvh->GetDelegate()->GetFrameTree()->GetFocusedFrame();
    if (!focused_frame)
        return nullptr;

    return focused_frame->current_frame_host();
}

void RenderWidgetHostViewAura::HandleParentBoundsChanged()
{
    SnapToPhysicalPixelBoundary();
#if defined(OS_WIN)
    if (legacy_render_widget_host_HWND_) {
        legacy_render_widget_host_HWND_->SetBounds(
            window_->GetBoundsInRootWindow());
    }
#endif
    if (!in_shutdown_) {
        // Send screen rects through the delegate if there is one. Not every
        // RenderWidgetHost has a delegate (for example, drop-down widgets).
        if (host_->delegate())
            host_->delegate()->SendScreenRects();
        else
            host_->SendScreenRects();
    }
}

void RenderWidgetHostViewAura::ParentHierarchyChanged()
{
    ancestor_window_observer_.reset(new WindowAncestorObserver(this));
    // Snap when we receive a hierarchy changed. http://crbug.com/388908.
    HandleParentBoundsChanged();
}

void RenderWidgetHostViewAura::Focus()
{
    // Make sure we have a FocusClient before attempting to Focus(). In some
    // situations we may not yet be in a valid Window hierarchy (such as reloading
    // after out of memory discarded the tab).
    aura::client::FocusClient* client = aura::client::GetFocusClient(window_);
    if (client)
        window_->Focus();
}

bool RenderWidgetHostViewAura::HasFocus() const
{
    return window_->HasFocus();
}

bool RenderWidgetHostViewAura::IsSurfaceAvailableForCopy() const
{
    return delegated_frame_host_ ? delegated_frame_host_->CanCopyToBitmap()
                                 : false;
}

bool RenderWidgetHostViewAura::IsShowing()
{
    return window_->IsVisible();
}

gfx::Rect RenderWidgetHostViewAura::GetViewBounds() const
{
    return window_->GetBoundsInScreen();
}

void RenderWidgetHostViewAura::SetBackgroundColor(SkColor color)
{
    if (color == background_color())
        return;
    RenderWidgetHostViewBase::SetBackgroundColor(color);
    bool opaque = GetBackgroundOpaque();
    host_->SetBackgroundOpaque(opaque);
    window_->layer()->SetFillsBoundsOpaquely(opaque);
    window_->layer()->SetColor(color);
}

bool RenderWidgetHostViewAura::IsMouseLocked()
{
    return event_handler_->mouse_locked();
}

gfx::Size RenderWidgetHostViewAura::GetVisibleViewportSize() const
{
    gfx::Rect requested_rect(GetRequestedRendererSize());
    requested_rect.Inset(insets_);
    return requested_rect.size();
}

void RenderWidgetHostViewAura::SetInsets(const gfx::Insets& insets)
{
    if (insets != insets_) {
        insets_ = insets;
        host_->WasResized();
    }
}

void RenderWidgetHostViewAura::FocusedNodeTouched(
    const gfx::Point& location_dips_screen,
    bool editable)
{
#if defined(OS_WIN)
    RenderViewHost* rvh = RenderViewHost::From(host_);
    if (rvh && rvh->GetDelegate())
        rvh->GetDelegate()->SetIsVirtualKeyboardRequested(editable);

    ui::OnScreenKeyboardDisplayManager* osk_display_manager = ui::OnScreenKeyboardDisplayManager::GetInstance();
    DCHECK(osk_display_manager);
    if (editable && host_ && host_->GetView() && host_->delegate()) {
        keyboard_observer_.reset(new WinScreenKeyboardObserver(
            host_, location_dips_screen, device_scale_factor_, window_));
        virtual_keyboard_requested_ = osk_display_manager->DisplayVirtualKeyboard(keyboard_observer_.get());
    } else {
        virtual_keyboard_requested_ = false;
        osk_display_manager->DismissVirtualKeyboard();
    }
#endif
}

void RenderWidgetHostViewAura::UpdateCursor(const WebCursor& cursor)
{
    current_cursor_ = cursor;
    const display::Display display = display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
    current_cursor_.SetDisplayInfo(display);
    UpdateCursorIfOverSelf();
}

void RenderWidgetHostViewAura::SetIsLoading(bool is_loading)
{
    is_loading_ = is_loading;
    UpdateCursorIfOverSelf();
}

void RenderWidgetHostViewAura::RenderProcessGone(base::TerminationStatus status,
    int error_code)
{
    UpdateCursorIfOverSelf();
    Destroy();
}

void RenderWidgetHostViewAura::Destroy()
{
    // Beware, this function is not called on all destruction paths. If |window_|
    // has been created, then it will implicitly end up calling
    // ~RenderWidgetHostViewAura when |window_| is destroyed. Otherwise, The
    // destructor is invoked directly from here. So all destruction/cleanup code
    // should happen there, not here.
    in_shutdown_ = true;
    if (window_)
        delete window_;
    else
        delete this;
}

void RenderWidgetHostViewAura::SetTooltipText(
    const base::string16& tooltip_text)
{
    tooltip_ = tooltip_text;
    aura::Window* root_window = window_->GetRootWindow();
    aura::client::TooltipClient* tooltip_client = aura::client::GetTooltipClient(root_window);
    if (tooltip_client) {
        tooltip_client->UpdateTooltip(window_);
        // Content tooltips should be visible indefinitely.
        tooltip_client->SetTooltipShownTimeout(window_, 0);
    }
}

gfx::Size RenderWidgetHostViewAura::GetRequestedRendererSize() const
{
    return delegated_frame_host_
        ? delegated_frame_host_->GetRequestedRendererSize()
        : RenderWidgetHostViewBase::GetRequestedRendererSize();
}

void RenderWidgetHostViewAura::CopyFromCompositingSurface(
    const gfx::Rect& src_subrect,
    const gfx::Size& dst_size,
    const ReadbackRequestCallback& callback,
    const SkColorType preferred_color_type)
{
    if (!delegated_frame_host_)
        return;
    delegated_frame_host_->CopyFromCompositingSurface(
        src_subrect, dst_size, callback, preferred_color_type);
}

void RenderWidgetHostViewAura::CopyFromCompositingSurfaceToVideoFrame(
    const gfx::Rect& src_subrect,
    const scoped_refptr<media::VideoFrame>& target,
    const base::Callback<void(const gfx::Rect&, bool)>& callback)
{
    if (!delegated_frame_host_)
        return;
    delegated_frame_host_->CopyFromCompositingSurfaceToVideoFrame(
        src_subrect, target, callback);
}

bool RenderWidgetHostViewAura::CanCopyToVideoFrame() const
{
    return delegated_frame_host_ ? delegated_frame_host_->CanCopyToVideoFrame()
                                 : false;
}

void RenderWidgetHostViewAura::BeginFrameSubscription(
    std::unique_ptr<RenderWidgetHostViewFrameSubscriber> subscriber)
{
    if (delegated_frame_host_)
        delegated_frame_host_->BeginFrameSubscription(std::move(subscriber));
}

void RenderWidgetHostViewAura::EndFrameSubscription()
{
    if (delegated_frame_host_)
        delegated_frame_host_->EndFrameSubscription();
}

#if defined(OS_WIN)
bool RenderWidgetHostViewAura::UsesNativeWindowFrame() const
{
    return (legacy_render_widget_host_HWND_ != NULL);
}

void RenderWidgetHostViewAura::UpdateMouseLockRegion()
{
    RECT window_rect = display::Screen::GetScreen()
                           ->DIPToScreenRectInWindow(window_, window_->GetBoundsInScreen())
                           .ToRECT();
    ::ClipCursor(&window_rect);
}

void RenderWidgetHostViewAura::OnLegacyWindowDestroyed()
{
    legacy_render_widget_host_HWND_ = NULL;
    legacy_window_destroyed_ = true;
}
#endif

void RenderWidgetHostViewAura::OnSwapCompositorFrame(
    uint32_t compositor_frame_sink_id,
    cc::CompositorFrame frame)
{
    TRACE_EVENT0("content", "RenderWidgetHostViewAura::OnSwapCompositorFrame");

    // Override the background color to the current compositor background.
    // This allows us to, when navigating to a new page, transfer this color to
    // that page. This allows us to pass this background color to new views on
    // navigation.
    SetBackgroundColor(frame.metadata.root_background_color);

    last_scroll_offset_ = frame.metadata.root_scroll_offset;
    if (frame.render_pass_list.empty())
        return;

    cc::Selection<gfx::SelectionBound> selection = frame.metadata.selection;
    if (IsUseZoomForDSFEnabled()) {
        float viewportToDIPScale = 1.0f / current_device_scale_factor_;
        gfx::PointF start_edge_top = selection.start.edge_top();
        gfx::PointF start_edge_bottom = selection.start.edge_bottom();
        gfx::PointF end_edge_top = selection.end.edge_top();
        gfx::PointF end_edge_bottom = selection.end.edge_bottom();

        start_edge_top.Scale(viewportToDIPScale);
        start_edge_bottom.Scale(viewportToDIPScale);
        end_edge_top.Scale(viewportToDIPScale);
        end_edge_bottom.Scale(viewportToDIPScale);

        selection.start.SetEdge(start_edge_top, start_edge_bottom);
        selection.end.SetEdge(end_edge_top, end_edge_bottom);
    }

    if (delegated_frame_host_) {
        delegated_frame_host_->SwapDelegatedFrame(compositor_frame_sink_id,
            std::move(frame));
    }
    SelectionUpdated(selection.is_editable, selection.is_empty_text_form_control,
        selection.start, selection.end);
}

void RenderWidgetHostViewAura::ClearCompositorFrame()
{
    if (delegated_frame_host_)
        delegated_frame_host_->ClearDelegatedFrame();
}

void RenderWidgetHostViewAura::DidStopFlinging()
{
    selection_controller_client_->OnScrollCompleted();
}

bool RenderWidgetHostViewAura::HasAcceleratedSurface(
    const gfx::Size& desired_size)
{
    // Aura doesn't use GetBackingStore for accelerated pages, so it doesn't
    // matter what is returned here as GetBackingStore is the only caller of this
    // method. TODO(jbates) implement this if other Aura code needs it.
    return false;
}

gfx::Rect RenderWidgetHostViewAura::GetBoundsInRootWindow()
{
    aura::Window* top_level = window_->GetToplevelWindow();
    gfx::Rect bounds(top_level->GetBoundsInScreen());

#if defined(OS_WIN)
    // TODO(zturner,iyengar): This will break when we remove support for NPAPI and
    // remove the legacy hwnd, so a better fix will need to be decided when that
    // happens.
    if (UsesNativeWindowFrame()) {
        // aura::Window doesn't take into account non-client area of native windows
        // (e.g. HWNDs), so for that case ask Windows directly what the bounds are.
        aura::WindowTreeHost* host = top_level->GetHost();
        if (!host)
            return top_level->GetBoundsInScreen();
        RECT window_rect = { 0 };
        HWND hwnd = host->GetAcceleratedWidget();
        ::GetWindowRect(hwnd, &window_rect);
        bounds = gfx::Rect(window_rect);

        // Maximized windows are outdented from the work area by the frame thickness
        // even though this "frame" is not painted.  This confuses code (and people)
        // that think of a maximized window as corresponding exactly to the work
        // area.  Correct for this by subtracting the frame thickness back off.
        if (::IsZoomed(hwnd)) {
            bounds.Inset(GetSystemMetrics(SM_CXSIZEFRAME),
                GetSystemMetrics(SM_CYSIZEFRAME));

            bounds.Inset(GetSystemMetrics(SM_CXPADDEDBORDER),
                GetSystemMetrics(SM_CXPADDEDBORDER));
        }
    }

    bounds = display::Screen::GetScreen()->ScreenToDIPRectInWindow(top_level, bounds);
#endif

    return bounds;
}

void RenderWidgetHostViewAura::WheelEventAck(
    const blink::WebMouseWheelEvent& event,
    InputEventAckState ack_result)
{
    if (overscroll_controller_) {
        overscroll_controller_->ReceivedEventACK(
            event, (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result));
    }
}

void RenderWidgetHostViewAura::GestureEventAck(
    const blink::WebGestureEvent& event,
    InputEventAckState ack_result)
{
    if (overscroll_controller_) {
        overscroll_controller_->ReceivedEventACK(
            event, (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result));
    }
}

void RenderWidgetHostViewAura::ProcessAckedTouchEvent(
    const TouchEventWithLatencyInfo& touch,
    InputEventAckState ack_result)
{
    ScopedVector<ui::TouchEvent> events;
    aura::WindowTreeHost* host = window_->GetHost();
    // |host| is NULL during tests.
    if (!host)
        return;

    // The TouchScrollStarted event is generated & consumed downstream from the
    // TouchEventQueue. So we don't expect an ACK up here.
    DCHECK(touch.event.type() != blink::WebInputEvent::TouchScrollStarted);

    ui::EventResult result = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
        ? ui::ER_HANDLED
        : ui::ER_UNHANDLED;

    blink::WebTouchPoint::State required_state;
    switch (touch.event.type()) {
    case blink::WebInputEvent::TouchStart:
        required_state = blink::WebTouchPoint::StatePressed;
        break;
    case blink::WebInputEvent::TouchEnd:
        required_state = blink::WebTouchPoint::StateReleased;
        break;
    case blink::WebInputEvent::TouchMove:
        required_state = blink::WebTouchPoint::StateMoved;
        break;
    case blink::WebInputEvent::TouchCancel:
        required_state = blink::WebTouchPoint::StateCancelled;
        break;
    default:
        required_state = blink::WebTouchPoint::StateUndefined;
        NOTREACHED();
        break;
    }

    // Only send acks for one changed touch point.
    bool sent_ack = false;
    for (size_t i = 0; i < touch.event.touchesLength; ++i) {
        if (touch.event.touches[i].state == required_state) {
            DCHECK(!sent_ack);
            host->dispatcher()->ProcessedTouchEvent(touch.event.uniqueTouchEventId,
                window_, result);
            sent_ack = true;
        }
    }
}

std::unique_ptr<SyntheticGestureTarget>
RenderWidgetHostViewAura::CreateSyntheticGestureTarget()
{
    return std::unique_ptr<SyntheticGestureTarget>(
        new SyntheticGestureTargetAura(host_));
}

InputEventAckState RenderWidgetHostViewAura::FilterInputEvent(
    const blink::WebInputEvent& input_event)
{
    bool consumed = false;
    if (input_event.type() == WebInputEvent::GestureFlingStart) {
        const WebGestureEvent& gesture_event = static_cast<const WebGestureEvent&>(input_event);
        // Zero-velocity touchpad flings are an Aura-specific signal that the
        // touchpad scroll has ended, and should not be forwarded to the renderer.
        if (gesture_event.sourceDevice == blink::WebGestureDeviceTouchpad && !gesture_event.data.flingStart.velocityX && !gesture_event.data.flingStart.velocityY) {
            consumed = true;
        }
    }

    if (overscroll_controller_)
        consumed |= overscroll_controller_->WillHandleEvent(input_event);

    // Touch events should always propagate to the renderer.
    if (WebTouchEvent::isTouchEventType(input_event.type()))
        return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;

    if (consumed && input_event.type() == blink::WebInputEvent::GestureFlingStart) {
        // Here we indicate that there was no consumer for this event, as
        // otherwise the fling animation system will try to run an animation
        // and will also expect a notification when the fling ends. Since
        // CrOS just uses the GestureFlingStart with zero-velocity as a means
        // of indicating that touchpad scroll has ended, we don't actually want
        // a fling animation. Note: Similar code exists in
        // RenderWidgetHostViewChildFrame::FilterInputEvent()
        return INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
    }

    return consumed ? INPUT_EVENT_ACK_STATE_CONSUMED
                    : INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
}

BrowserAccessibilityManager*
RenderWidgetHostViewAura::CreateBrowserAccessibilityManager(
    BrowserAccessibilityDelegate* delegate, bool for_root_frame)
{
    BrowserAccessibilityManager* manager = NULL;
#if defined(OS_WIN)
    manager = new BrowserAccessibilityManagerWin(
        BrowserAccessibilityManagerWin::GetEmptyDocument(), delegate);
#else
    manager = BrowserAccessibilityManager::Create(
        BrowserAccessibilityManager::GetEmptyDocument(), delegate);
#endif
    return manager;
}

gfx::AcceleratedWidget
RenderWidgetHostViewAura::AccessibilityGetAcceleratedWidget()
{
#if defined(OS_WIN)
    if (legacy_render_widget_host_HWND_)
        return legacy_render_widget_host_HWND_->hwnd();
#endif
    return gfx::kNullAcceleratedWidget;
}

gfx::NativeViewAccessible
RenderWidgetHostViewAura::AccessibilityGetNativeViewAccessible()
{
#if defined(OS_WIN)
    if (legacy_render_widget_host_HWND_)
        return legacy_render_widget_host_HWND_->window_accessible();
#endif
    return NULL;
}

bool RenderWidgetHostViewAura::LockMouse()
{
    return event_handler_->LockMouse();
}

void RenderWidgetHostViewAura::UnlockMouse()
{
    event_handler_->UnlockMouse();
}

////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, ui::TextInputClient implementation:
void RenderWidgetHostViewAura::SetCompositionText(
    const ui::CompositionText& composition)
{
    if (!text_input_manager_ || !text_input_manager_->GetActiveWidget())
        return;

    // TODO(suzhe): convert both renderer_host and renderer to use
    // ui::CompositionText.
    std::vector<blink::WebCompositionUnderline> underlines;
    underlines.reserve(composition.underlines.size());
    for (std::vector<ui::CompositionUnderline>::const_iterator it = composition.underlines.begin();
         it != composition.underlines.end(); ++it) {
        underlines.push_back(
            blink::WebCompositionUnderline(static_cast<unsigned>(it->start_offset),
                static_cast<unsigned>(it->end_offset),
                it->color,
                it->thick,
                it->background_color));
    }

    // TODO(suzhe): due to a bug of webkit, we can't use selection range with
    // composition string. See: https://bugs.webkit.org/show_bug.cgi?id=37788
    text_input_manager_->GetActiveWidget()->ImeSetComposition(
        composition.text, underlines, gfx::Range::InvalidRange(),
        composition.selection.end(), composition.selection.end());

    has_composition_text_ = !composition.text.empty();
}

void RenderWidgetHostViewAura::ConfirmCompositionText()
{
    if (text_input_manager_ && text_input_manager_->GetActiveWidget() && has_composition_text_) {
        text_input_manager_->GetActiveWidget()->ImeFinishComposingText(false);
    }
    has_composition_text_ = false;
}

void RenderWidgetHostViewAura::ClearCompositionText()
{
    if (text_input_manager_ && text_input_manager_->GetActiveWidget() && has_composition_text_)
        text_input_manager_->GetActiveWidget()->ImeCancelComposition();
    has_composition_text_ = false;
}

void RenderWidgetHostViewAura::InsertText(const base::string16& text)
{
    DCHECK_NE(GetTextInputType(), ui::TEXT_INPUT_TYPE_NONE);

    if (text_input_manager_ && text_input_manager_->GetActiveWidget()) {
        if (text.length())
            text_input_manager_->GetActiveWidget()->ImeCommitText(
                text, std::vector<blink::WebCompositionUnderline>(),
                gfx::Range::InvalidRange(), 0);
        else if (has_composition_text_)
            text_input_manager_->GetActiveWidget()->ImeFinishComposingText(false);
    }
    has_composition_text_ = false;
}

void RenderWidgetHostViewAura::InsertChar(const ui::KeyEvent& event)
{
    if (popup_child_host_view_ && popup_child_host_view_->NeedsInputGrab()) {
        popup_child_host_view_->InsertChar(event);
        return;
    }

    // Ignore character messages for VKEY_RETURN sent on CTRL+M. crbug.com/315547
    // TODO(wjmaclean): can host_ ever be null?
    if (host_ && (event_handler_->accept_return_character() || event.GetCharacter() != ui::VKEY_RETURN)) {
        // Send a blink::WebInputEvent::Char event to |host_|.
        ForwardKeyboardEvent(NativeWebKeyboardEvent(event, event.GetCharacter()));
    }
}

ui::TextInputType RenderWidgetHostViewAura::GetTextInputType() const
{
    if (text_input_manager_ && text_input_manager_->GetTextInputState())
        return text_input_manager_->GetTextInputState()->type;
    return ui::TEXT_INPUT_TYPE_NONE;
}

ui::TextInputMode RenderWidgetHostViewAura::GetTextInputMode() const
{
    if (text_input_manager_ && text_input_manager_->GetTextInputState())
        return text_input_manager_->GetTextInputState()->mode;
    return ui::TEXT_INPUT_MODE_DEFAULT;
}

base::i18n::TextDirection RenderWidgetHostViewAura::GetTextDirection() const
{
    NOTIMPLEMENTED();
    return base::i18n::UNKNOWN_DIRECTION;
}

int RenderWidgetHostViewAura::GetTextInputFlags() const
{
    if (text_input_manager_ && text_input_manager_->GetTextInputState())
        return text_input_manager_->GetTextInputState()->flags;
    return 0;
}

bool RenderWidgetHostViewAura::CanComposeInline() const
{
    if (text_input_manager_ && text_input_manager_->GetTextInputState())
        return text_input_manager_->GetTextInputState()->can_compose_inline;
    return true;
}

gfx::Rect RenderWidgetHostViewAura::ConvertRectToScreen(
    const gfx::Rect& rect) const
{
    gfx::Point origin = rect.origin();
    gfx::Point end = gfx::Point(rect.right(), rect.bottom());

    aura::Window* root_window = window_->GetRootWindow();
    if (!root_window)
        return rect;
    aura::client::ScreenPositionClient* screen_position_client = aura::client::GetScreenPositionClient(root_window);
    if (!screen_position_client)
        return rect;
    screen_position_client->ConvertPointToScreen(window_, &origin);
    screen_position_client->ConvertPointToScreen(window_, &end);
    return gfx::Rect(origin.x(),
        origin.y(),
        end.x() - origin.x(),
        end.y() - origin.y());
}

gfx::Rect RenderWidgetHostViewAura::ConvertRectFromScreen(
    const gfx::Rect& rect) const
{
    gfx::Point origin = rect.origin();
    gfx::Point end = gfx::Point(rect.right(), rect.bottom());

    aura::Window* root_window = window_->GetRootWindow();
    if (root_window) {
        aura::client::ScreenPositionClient* screen_position_client = aura::client::GetScreenPositionClient(root_window);
        screen_position_client->ConvertPointFromScreen(window_, &origin);
        screen_position_client->ConvertPointFromScreen(window_, &end);
        return gfx::Rect(origin.x(),
            origin.y(),
            end.x() - origin.x(),
            end.y() - origin.y());
    }

    return rect;
}

gfx::Rect RenderWidgetHostViewAura::GetCaretBounds() const
{
    if (!text_input_manager_ || !text_input_manager_->GetActiveWidget())
        return gfx::Rect();

    const TextInputManager::SelectionRegion* region = text_input_manager_->GetSelectionRegion();
    return ConvertRectToScreen(
        gfx::RectBetweenSelectionBounds(region->anchor, region->focus));
}

bool RenderWidgetHostViewAura::GetCompositionCharacterBounds(
    uint32_t index,
    gfx::Rect* rect) const
{
    DCHECK(rect);

    if (!text_input_manager_ || !text_input_manager_->GetActiveWidget())
        return false;

    const TextInputManager::CompositionRangeInfo* composition_range_info = text_input_manager_->GetCompositionRangeInfo();

    if (index >= composition_range_info->character_bounds.size())
        return false;
    *rect = ConvertRectToScreen(composition_range_info->character_bounds[index]);
    return true;
}

bool RenderWidgetHostViewAura::HasCompositionText() const
{
    return has_composition_text_;
}

bool RenderWidgetHostViewAura::GetTextRange(gfx::Range* range) const
{
    if (!text_input_manager_ || !GetFocusedWidget())
        return false;

    const TextInputManager::TextSelection* selection = text_input_manager_->GetTextSelection(GetFocusedWidget()->GetView());
    if (!selection)
        return false;

    range->set_start(selection->offset);
    range->set_end(selection->offset + selection->text.length());
    return true;
}

bool RenderWidgetHostViewAura::GetCompositionTextRange(
    gfx::Range* range) const
{
    // TODO(suzhe): implement this method when fixing http://crbug.com/55130.
    NOTIMPLEMENTED();
    return false;
}

bool RenderWidgetHostViewAura::GetSelectionRange(gfx::Range* range) const
{
    if (!text_input_manager_ || !GetFocusedWidget())
        return false;

    const TextInputManager::TextSelection* selection = text_input_manager_->GetTextSelection(GetFocusedWidget()->GetView());
    if (!selection)
        return false;

    range->set_start(selection->range.start());
    range->set_end(selection->range.end());
    return true;
}

bool RenderWidgetHostViewAura::SetSelectionRange(const gfx::Range& range)
{
    // TODO(suzhe): implement this method when fixing http://crbug.com/55130.
    NOTIMPLEMENTED();
    return false;
}

bool RenderWidgetHostViewAura::DeleteRange(const gfx::Range& range)
{
    // TODO(suzhe): implement this method when fixing http://crbug.com/55130.
    NOTIMPLEMENTED();
    return false;
}

bool RenderWidgetHostViewAura::GetTextFromRange(
    const gfx::Range& range,
    base::string16* text) const
{
    if (!text_input_manager_ || !GetFocusedWidget())
        return false;

    const TextInputManager::TextSelection* selection = text_input_manager_->GetTextSelection(GetFocusedWidget()->GetView());
    if (!selection)
        return false;

    gfx::Range selection_text_range(selection->offset,
        selection->offset + selection->text.length());

    if (!selection_text_range.Contains(range)) {
        text->clear();
        return false;
    }
    if (selection_text_range.EqualsIgnoringDirection(range)) {
        // Avoid calling substr whose performance is low.
        *text = selection->text;
    } else {
        *text = selection->text.substr(range.GetMin() - selection->offset,
            range.length());
    }
    return true;
}

void RenderWidgetHostViewAura::OnInputMethodChanged()
{
    // TODO(wjmaclean): can host_ ever be null?
    if (!host_)
        return;

    // TODO(suzhe): implement the newly added “locale” property of HTML DOM
    // TextEvent.
}

bool RenderWidgetHostViewAura::ChangeTextDirectionAndLayoutAlignment(
    base::i18n::TextDirection direction)
{
    if (!GetTextInputManager() && !GetTextInputManager()->GetActiveWidget())
        return false;

    GetTextInputManager()->GetActiveWidget()->UpdateTextDirection(
        direction == base::i18n::RIGHT_TO_LEFT
            ? blink::WebTextDirectionRightToLeft
            : blink::WebTextDirectionLeftToRight);
    GetTextInputManager()->GetActiveWidget()->NotifyTextDirection();
    return true;
}

void RenderWidgetHostViewAura::ExtendSelectionAndDelete(
    size_t before, size_t after)
{
    RenderFrameHostImpl* rfh = GetFocusedFrame();
    if (rfh)
        rfh->ExtendSelectionAndDelete(before, after);
}

void RenderWidgetHostViewAura::EnsureCaretNotInRect(const gfx::Rect& rect)
{
    gfx::Rect rect_in_local_space = ConvertRectFromScreen(rect);
    gfx::Rect hiding_area_in_this_window = gfx::IntersectRects(rect_in_local_space, window_->bounds());

    if (hiding_area_in_this_window.IsEmpty())
        return;

    host_->ScrollFocusedEditableNodeIntoRect(
        gfx::SubtractRects(window_->bounds(), hiding_area_in_this_window));
}

bool RenderWidgetHostViewAura::IsTextEditCommandEnabled(
    ui::TextEditCommand command) const
{
    return false;
}

void RenderWidgetHostViewAura::SetTextEditCommandForNextKeyEvent(
    ui::TextEditCommand command) { }

////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, display::DisplayObserver implementation:

void RenderWidgetHostViewAura::OnDisplayAdded(
    const display::Display& new_display) { }

void RenderWidgetHostViewAura::OnDisplayRemoved(
    const display::Display& old_display) { }

void RenderWidgetHostViewAura::OnDisplayMetricsChanged(
    const display::Display& display,
    uint32_t metrics)
{
    // The screen info should be updated regardless of the metric change.
    display::Screen* screen = display::Screen::GetScreen();
    if (display.id() == screen->GetDisplayNearestWindow(window_).id()) {
        UpdateScreenInfo(window_);
        current_cursor_.SetDisplayInfo(display);
        UpdateCursorIfOverSelf();
    }
}

////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, aura::WindowDelegate implementation:

gfx::Size RenderWidgetHostViewAura::GetMinimumSize() const
{
    return gfx::Size();
}

gfx::Size RenderWidgetHostViewAura::GetMaximumSize() const
{
    return gfx::Size();
}

void RenderWidgetHostViewAura::OnBoundsChanged(const gfx::Rect& old_bounds,
    const gfx::Rect& new_bounds)
{
    base::AutoReset<bool> in_bounds_changed(&in_bounds_changed_, true);
    // We care about this whenever RenderWidgetHostViewAura is not owned by a
    // WebContentsViewAura since changes to the Window's bounds need to be
    // messaged to the renderer.  WebContentsViewAura invokes SetSize() or
    // SetBounds() itself.  No matter how we got here, any redundant calls are
    // harmless.
    SetSize(new_bounds.size());

    if (GetInputMethod())
        GetInputMethod()->OnCaretBoundsChanged(this);
}

gfx::NativeCursor RenderWidgetHostViewAura::GetCursor(const gfx::Point& point)
{
    if (mouse_locked_)
        return ui::kCursorNone;
    return current_cursor_.GetNativeCursor();
}

int RenderWidgetHostViewAura::GetNonClientComponent(
    const gfx::Point& point) const
{
    return HTCLIENT;
}

bool RenderWidgetHostViewAura::ShouldDescendIntoChildForEventHandling(
    aura::Window* child,
    const gfx::Point& location)
{
    return true;
}

bool RenderWidgetHostViewAura::CanFocus()
{
    return popup_type_ == blink::WebPopupTypeNone;
}

void RenderWidgetHostViewAura::OnCaptureLost()
{
    host_->LostCapture();
}

void RenderWidgetHostViewAura::OnPaint(const ui::PaintContext& context)
{
    NOTREACHED();
}

void RenderWidgetHostViewAura::OnDeviceScaleFactorChanged(
    float device_scale_factor)
{
    if (!window_->GetRootWindow())
        return;

    RenderWidgetHostImpl* host = RenderWidgetHostImpl::From(GetRenderWidgetHost());
    if (host && host->delegate())
        host->delegate()->UpdateDeviceScaleFactor(device_scale_factor);

    device_scale_factor_ = device_scale_factor;
    const display::Display display = display::Screen::GetScreen()->GetDisplayNearestWindow(window_);
    DCHECK_EQ(device_scale_factor, display.device_scale_factor());
    current_cursor_.SetDisplayInfo(display);
    SnapToPhysicalPixelBoundary();
}

void RenderWidgetHostViewAura::OnWindowDestroying(aura::Window* window)
{
#if defined(OS_WIN)
    // The LegacyRenderWidgetHostHWND instance is destroyed when its window is
    // destroyed. Normally we control when that happens via the Destroy call
    // in the dtor. However there may be cases where the window is destroyed
    // by Windows, i.e. the parent window is destroyed before the
    // RenderWidgetHostViewAura instance goes away etc. To avoid that we
    // destroy the LegacyRenderWidgetHostHWND instance here.
    if (legacy_render_widget_host_HWND_) {
        legacy_render_widget_host_HWND_->set_host(NULL);
        legacy_render_widget_host_HWND_->Destroy();
        // The Destroy call above will delete the LegacyRenderWidgetHostHWND
        // instance.
        legacy_render_widget_host_HWND_ = NULL;
    }
#endif

    // Make sure that the input method no longer references to this object before
    // this object is removed from the root window (i.e. this object loses access
    // to the input method).
    DetachFromInputMethod();

    if (overscroll_controller_)
        overscroll_controller_->Reset();
}

void RenderWidgetHostViewAura::OnWindowDestroyed(aura::Window* window)
{
    // This is not called on all destruction paths (e.g. if this view was never
    // inialized properly to create the window). So the destruction/cleanup code
    // that do not depend on |window_| should happen in the destructor, not here.
    delete this;
}

void RenderWidgetHostViewAura::OnWindowTargetVisibilityChanged(bool visible)
{
}

bool RenderWidgetHostViewAura::HasHitTestMask() const
{
    return false;
}

void RenderWidgetHostViewAura::GetHitTestMask(gfx::Path* mask) const
{
}

////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, ui::EventHandler implementation:

void RenderWidgetHostViewAura::OnKeyEvent(ui::KeyEvent* event)
{
    event_handler_->OnKeyEvent(event);
}

void RenderWidgetHostViewAura::OnMouseEvent(ui::MouseEvent* event)
{
    event_handler_->OnMouseEvent(event);
}

cc::FrameSinkId RenderWidgetHostViewAura::FrameSinkIdAtPoint(
    cc::SurfaceHittestDelegate* delegate,
    const gfx::Point& point,
    gfx::Point* transformed_point)
{
    DCHECK(device_scale_factor_ != 0.0f);

    // The surface hittest happens in device pixels, so we need to convert the
    // |point| from DIPs to pixels before hittesting.
    gfx::Point point_in_pixels = gfx::ConvertPointToPixel(device_scale_factor_, point);
    // TODO: this shouldn't be used with aura-mus, so that the null check so
    // go away and become a DCHECK.
    cc::SurfaceId id = delegated_frame_host_
        ? delegated_frame_host_->SurfaceIdAtPoint(
            delegate, point_in_pixels, transformed_point)
        : cc::SurfaceId();
    *transformed_point = gfx::ConvertPointToDIP(device_scale_factor_, *transformed_point);

    // It is possible that the renderer has not yet produced a surface, in which
    // case we return our current namespace.
    if (!id.is_valid())
        return GetFrameSinkId();
    return id.frame_sink_id();
}

void RenderWidgetHostViewAura::ProcessMouseEvent(
    const blink::WebMouseEvent& event,
    const ui::LatencyInfo& latency)
{
    host_->ForwardMouseEventWithLatencyInfo(event, latency);
}

void RenderWidgetHostViewAura::ProcessMouseWheelEvent(
    const blink::WebMouseWheelEvent& event,
    const ui::LatencyInfo& latency)
{
    host_->ForwardWheelEventWithLatencyInfo(event, latency);
}

void RenderWidgetHostViewAura::ProcessTouchEvent(
    const blink::WebTouchEvent& event,
    const ui::LatencyInfo& latency)
{
    host_->ForwardTouchEventWithLatencyInfo(event, latency);
}

void RenderWidgetHostViewAura::ProcessGestureEvent(
    const blink::WebGestureEvent& event,
    const ui::LatencyInfo& latency)
{
    host_->ForwardGestureEventWithLatencyInfo(event, latency);
}

bool RenderWidgetHostViewAura::TransformPointToLocalCoordSpace(
    const gfx::Point& point,
    const cc::SurfaceId& original_surface,
    gfx::Point* transformed_point)
{
    // Transformations use physical pixels rather than DIP, so conversion
    // is necessary.
    gfx::Point point_in_pixels = gfx::ConvertPointToPixel(device_scale_factor_, point);
    // TODO: this shouldn't be used with aura-mus, so that the null check so
    // go away and become a DCHECK.
    if (delegated_frame_host_ && !delegated_frame_host_->TransformPointToLocalCoordSpace(point_in_pixels, original_surface, transformed_point))
        return false;
    *transformed_point = gfx::ConvertPointToDIP(device_scale_factor_, *transformed_point);
    return true;
}

bool RenderWidgetHostViewAura::TransformPointToCoordSpaceForView(
    const gfx::Point& point,
    RenderWidgetHostViewBase* target_view,
    gfx::Point* transformed_point)
{
    if (target_view == this || !delegated_frame_host_) {
        *transformed_point = point;
        return true;
    }

    // In TransformPointToLocalCoordSpace() there is a Point-to-Pixel conversion,
    // but it is not necessary here because the final target view is responsible
    // for converting before computing the final transform.
    return delegated_frame_host_->TransformPointToCoordSpaceForView(
        point, target_view, transformed_point);
}

void RenderWidgetHostViewAura::FocusedNodeChanged(
    bool editable,
    const gfx::Rect& node_bounds_in_screen)
{
#if defined(OS_WIN)
    if (!editable && virtual_keyboard_requested_) {
        virtual_keyboard_requested_ = false;

        RenderViewHost* rvh = RenderViewHost::From(host_);
        if (rvh && rvh->GetDelegate())
            rvh->GetDelegate()->SetIsVirtualKeyboardRequested(false);

        DCHECK(ui::OnScreenKeyboardDisplayManager::GetInstance());
        ui::OnScreenKeyboardDisplayManager::GetInstance()->DismissVirtualKeyboard();
    }
#endif
}

void RenderWidgetHostViewAura::OnScrollEvent(ui::ScrollEvent* event)
{
    event_handler_->OnScrollEvent(event);
}

void RenderWidgetHostViewAura::OnTouchEvent(ui::TouchEvent* event)
{
    event_handler_->OnTouchEvent(event);
}

void RenderWidgetHostViewAura::OnGestureEvent(ui::GestureEvent* event)
{
    event_handler_->OnGestureEvent(event);
}

////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, aura::client::ActivationDelegate implementation:

bool RenderWidgetHostViewAura::ShouldActivate() const
{
    aura::WindowTreeHost* host = window_->GetHost();
    if (!host)
        return true;
    const ui::Event* event = host->dispatcher()->current_event();
    if (!event)
        return true;
    return is_fullscreen_;
}

////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, aura::client::CursorClientObserver implementation:

void RenderWidgetHostViewAura::OnCursorVisibilityChanged(bool is_visible)
{
    NotifyRendererOfCursorVisibilityState(is_visible);
}

////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, aura::client::FocusChangeObserver implementation:

void RenderWidgetHostViewAura::OnWindowFocused(aura::Window* gained_focus,
    aura::Window* lost_focus)
{
    DCHECK(window_ == gained_focus || window_ == lost_focus);
    if (window_ == gained_focus) {
        // We need to honor input bypass if the associated tab is does not want
        // input. This gives the current focused window a chance to be the text
        // input client and handle events.
        if (host_->ignore_input_events())
            return;

        host_->GotFocus();
        host_->SetActive(true);

        ui::InputMethod* input_method = GetInputMethod();
        if (input_method) {
            // Ask the system-wide IME to send all TextInputClient messages to |this|
            // object.
            input_method->SetFocusedTextInputClient(this);
        }

        BrowserAccessibilityManager* manager = host_->GetRootBrowserAccessibilityManager();
        if (manager)
            manager->OnWindowFocused();
    } else if (window_ == lost_focus) {
        host_->SetActive(false);
        host_->Blur();

        DetachFromInputMethod();

        selection_controller_->HideAndDisallowShowingAutomatically();

        if (overscroll_controller_)
            overscroll_controller_->Cancel();

        BrowserAccessibilityManager* manager = host_->GetRootBrowserAccessibilityManager();
        if (manager)
            manager->OnWindowBlurred();

        // If we lose the focus while fullscreen, close the window; Pepper Flash
        // won't do it for us (unlike NPAPI Flash). However, we do not close the
        // window if we lose the focus to a window on another display.
        display::Screen* screen = display::Screen::GetScreen();
        bool focusing_other_display = gained_focus && screen->GetNumDisplays() > 1 && (screen->GetDisplayNearestWindow(window_).id() != screen->GetDisplayNearestWindow(gained_focus).id());
        if (is_fullscreen_ && !in_shutdown_ && !focusing_other_display) {
#if defined(OS_WIN)
            // On Windows, if we are switching to a non Aura Window on a different
            // screen we should not close the fullscreen window.
            if (!gained_focus) {
                POINT point = { 0 };
                ::GetCursorPos(&point);
                if (screen->GetDisplayNearestWindow(window_).id() != screen->GetDisplayNearestPoint(gfx::Point(point)).id())
                    return;
            }
#endif
            Shutdown();
            return;
        }

        // Close the child popup window if we lose focus (e.g. due to a JS alert or
        // system modal dialog). This is particularly important if
        // |popup_child_host_view_| has mouse capture.
        if (popup_child_host_view_)
            popup_child_host_view_->Shutdown();
    }
}

////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, aura::WindowTreeHostObserver implementation:

void RenderWidgetHostViewAura::OnHostMovedInPixels(
    const aura::WindowTreeHost* host,
    const gfx::Point& new_origin_in_pixels)
{
    TRACE_EVENT1("ui", "RenderWidgetHostViewAura::OnHostMovedInPixels",
        "new_origin_in_pixels", new_origin_in_pixels.ToString());

    UpdateScreenInfo(window_);
}

////////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewAura, private:

RenderWidgetHostViewAura::~RenderWidgetHostViewAura()
{
    // Ask the RWH to drop reference to us.
    if (!is_guest_view_hack_)
        host_->ViewDestroyed();

    selection_controller_.reset();
    selection_controller_client_.reset();

    delegated_frame_host_.reset();
    window_observer_.reset();
    if (window_) {
        if (window_->GetHost())
            window_->GetHost()->RemoveObserver(this);
        UnlockMouse();
        aura::client::SetTooltipText(window_, NULL);
        display::Screen::GetScreen()->RemoveObserver(this);

        // This call is usually no-op since |this| object is already removed from
        // the Aura root window and we don't have a way to get an input method
        // object associated with the window, but just in case.
        DetachFromInputMethod();
    }
    if (popup_parent_host_view_) {
        DCHECK(popup_parent_host_view_->popup_child_host_view_ == NULL || popup_parent_host_view_->popup_child_host_view_ == this);
        popup_parent_host_view_->SetPopupChild(nullptr);
    }
    if (popup_child_host_view_) {
        DCHECK(popup_child_host_view_->popup_parent_host_view_ == NULL || popup_child_host_view_->popup_parent_host_view_ == this);
        popup_child_host_view_->popup_parent_host_view_ = NULL;
    }
    event_filter_for_popup_exit_.reset();

#if defined(OS_WIN)
    // The LegacyRenderWidgetHostHWND window should have been destroyed in
    // RenderWidgetHostViewAura::OnWindowDestroying and the pointer should
    // be set to NULL.
    DCHECK(!legacy_render_widget_host_HWND_);
    if (virtual_keyboard_requested_) {
        DCHECK(keyboard_observer_.get());
        ui::OnScreenKeyboardDisplayManager* osk_display_manager = ui::OnScreenKeyboardDisplayManager::GetInstance();
        DCHECK(osk_display_manager);
        osk_display_manager->RemoveObserver(keyboard_observer_.get());
    }

#endif

    if (text_input_manager_)
        text_input_manager_->RemoveObserver(this);
}

void RenderWidgetHostViewAura::CreateAuraWindow(ui::wm::WindowType type)
{
    DCHECK(!window_);
    window_ = new aura::Window(this);
    window_->SetName("RenderWidgetHostViewAura");
    event_handler_->set_window(window_);
    window_observer_.reset(new WindowObserver(this));

    aura::client::SetTooltipText(window_, &tooltip_);
    aura::client::SetActivationDelegate(window_, this);
    aura::client::SetFocusChangeObserver(window_, this);
    display::Screen::GetScreen()->AddObserver(this);

    window_->SetType(type);
    window_->Init(ui::LAYER_SOLID_COLOR);
    window_->layer()->SetColor(background_color_);

    if (!IsMus())
        return;

    // Connect to the renderer, pass it a WindowTreeClient interface request
    // and embed that client inside our mus window.
    mojom::RenderWidgetWindowTreeClientFactoryPtr factory;
    host_->GetProcess()->GetRemoteInterfaces()->GetInterface(&factory);

    ui::mojom::WindowTreeClientPtr window_tree_client;
    factory->CreateWindowTreeClientForRenderWidget(
        host_->GetRoutingID(), mojo::MakeRequest(&window_tree_client));
    aura::WindowPortMus::Get(window_)->Embed(
        std::move(window_tree_client),
        ui::mojom::kEmbedFlagEmbedderInterceptsEvents,
        base::Bind(&EmbedCallback));
}

void RenderWidgetHostViewAura::CreateDelegatedFrameHostClient()
{
    if (IsMus())
        return;

    // GuestViews have two RenderWidgetHostViews and so we need to make sure
    // we don't have FrameSinkId collisions.
    ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
    cc::FrameSinkId frame_sink_id = is_guest_view_hack_
        ? factory->GetContextFactoryPrivate()->AllocateFrameSinkId()
        : cc::FrameSinkId(
            base::checked_cast<uint32_t>(host_->GetProcess()->GetID()),
            base::checked_cast<uint32_t>(host_->GetRoutingID()));
    // Tests may set |delegated_frame_host_client_|.
    if (!delegated_frame_host_client_) {
        delegated_frame_host_client_ = base::MakeUnique<DelegatedFrameHostClientAura>(this);
    }
    delegated_frame_host_ = base::MakeUnique<DelegatedFrameHost>(
        frame_sink_id, delegated_frame_host_client_.get());

    // Let the page-level input event router know about our surface ID
    // namespace for surface-based hit testing.
    if (host_->delegate() && host_->delegate()->GetInputEventRouter()) {
        host_->delegate()->GetInputEventRouter()->AddFrameSinkIdOwner(
            GetFrameSinkId(), this);
    }
}

void RenderWidgetHostViewAura::UpdateCursorIfOverSelf()
{
    if (host_->GetProcess()->FastShutdownStarted())
        return;

    aura::Window* root_window = window_->GetRootWindow();
    if (!root_window)
        return;

    display::Screen* screen = display::Screen::GetScreen();
    DCHECK(screen);

    gfx::Point cursor_screen_point = screen->GetCursorScreenPoint();

#if !defined(OS_CHROMEOS)
    // Ignore cursor update messages if the window under the cursor is not us.
    aura::Window* window_at_screen_point = screen->GetWindowAtScreenPoint(
        cursor_screen_point);
#if defined(OS_WIN)
    // On Windows we may fail to retrieve the aura Window at the current cursor
    // position. This is because the WindowFromPoint API may return the legacy
    // window which is not associated with an aura Window. In this case we need
    // to get the aura window for the parent of the legacy window.
    if (!window_at_screen_point && legacy_render_widget_host_HWND_) {
        HWND hwnd_at_point = ::WindowFromPoint(cursor_screen_point.ToPOINT());

        if (hwnd_at_point == legacy_render_widget_host_HWND_->hwnd())
            hwnd_at_point = legacy_render_widget_host_HWND_->GetParent();

        display::win::ScreenWin* screen_win = static_cast<display::win::ScreenWin*>(screen);
        window_at_screen_point = screen_win->GetNativeWindowFromHWND(
            hwnd_at_point);
    }
#endif // defined(OS_WIN)
    if (!window_at_screen_point || (window_at_screen_point->GetRootWindow() != root_window)) {
        return;
    }
#endif // !defined(OS_CHROMEOS)

    gfx::Point root_window_point = cursor_screen_point;
    aura::client::ScreenPositionClient* screen_position_client = aura::client::GetScreenPositionClient(root_window);
    if (screen_position_client) {
        screen_position_client->ConvertPointFromScreen(
            root_window, &root_window_point);
    }

    if (root_window->GetEventHandlerForPoint(root_window_point) != window_)
        return;

    gfx::NativeCursor cursor = current_cursor_.GetNativeCursor();
    // Do not show loading cursor when the cursor is currently hidden.
    if (is_loading_ && cursor != ui::kCursorNone)
        cursor = ui::kCursorPointer;

    aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(root_window);
    if (cursor_client) {
        cursor_client->SetCursor(cursor);
    }
}

ui::InputMethod* RenderWidgetHostViewAura::GetInputMethod() const
{
    if (!window_)
        return nullptr;
    aura::Window* root_window = window_->GetRootWindow();
    if (!root_window)
        return nullptr;
    return root_window->GetHost()->GetInputMethod();
}

void RenderWidgetHostViewAura::Shutdown()
{
    if (!in_shutdown_) {
        in_shutdown_ = true;
        host_->ShutdownAndDestroyWidget(true);
    }
}

bool RenderWidgetHostViewAura::NeedsInputGrab()
{
    return popup_type_ == blink::WebPopupTypePage;
}

bool RenderWidgetHostViewAura::NeedsMouseCapture()
{
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
    return NeedsInputGrab();
#endif
    return false;
}

void RenderWidgetHostViewAura::SetTooltipsEnabled(bool enable)
{
    if (enable) {
        tooltip_disabler_.reset();
    } else {
        tooltip_disabler_.reset(
            new aura::client::ScopedTooltipDisabler(window_->GetRootWindow()));
    }
}

void RenderWidgetHostViewAura::ShowContextMenu(
    const ContextMenuParams& params)
{
    // Use RenderViewHostDelegate to get to the WebContentsViewAura, which will
    // actually show the disambiguation popup.
    RenderViewHost* rvh = RenderViewHost::From(host_);
    if (!rvh)
        return;

    RenderViewHostDelegate* delegate = rvh->GetDelegate();
    if (!delegate)
        return;

    RenderViewHostDelegateView* delegate_view = delegate->GetDelegateView();
    if (!delegate_view)
        return;
    delegate_view->ShowContextMenu(GetFocusedFrame(), params);
}

void RenderWidgetHostViewAura::NotifyRendererOfCursorVisibilityState(
    bool is_visible)
{
    if (host_->is_hidden() || (cursor_visibility_state_in_renderer_ == VISIBLE && is_visible) || (cursor_visibility_state_in_renderer_ == NOT_VISIBLE && !is_visible))
        return;

    cursor_visibility_state_in_renderer_ = is_visible ? VISIBLE : NOT_VISIBLE;
    host_->SendCursorVisibilityState(is_visible);
}

void RenderWidgetHostViewAura::SetOverscrollControllerEnabled(bool enabled)
{
    if (!enabled)
        overscroll_controller_.reset();
    else if (!overscroll_controller_)
        overscroll_controller_.reset(new OverscrollController());
}

void RenderWidgetHostViewAura::SnapToPhysicalPixelBoundary()
{
    // The top left corner of our view in window coordinates might not land on a
    // device pixel boundary if we have a non-integer device scale. In that case,
    // to avoid the web contents area looking blurry we translate the web contents
    // in the +x, +y direction to land on the nearest pixel boundary. This may
    // cause the bottom and right edges to be clipped slightly, but that's ok.
#if defined(OS_CHROMEOS)
    aura::Window* snapped = window_->GetToplevelWindow();
#else
    aura::Window* snapped = window_->GetRootWindow();
#endif

    if (snapped && snapped != window_)
        ui::SnapLayerToPhysicalPixelBoundary(snapped->layer(), window_->layer());

    has_snapped_to_boundary_ = true;
}

bool RenderWidgetHostViewAura::OnShowContextMenu(
    const ContextMenuParams& params)
{
#if defined(OS_WIN)
    event_handler_->SetContextMenuParams(params);
    return params.source_type != ui::MENU_SOURCE_LONG_PRESS;
#else
    return true;
#endif // defined(OS_WIN)
}

void RenderWidgetHostViewAura::SetSelectionControllerClientForTest(
    std::unique_ptr<TouchSelectionControllerClientAura> client)
{
    selection_controller_client_.swap(client);
    CreateSelectionController();
}

void RenderWidgetHostViewAura::InternalSetBounds(const gfx::Rect& rect)
{
    SnapToPhysicalPixelBoundary();
    // Don't recursively call SetBounds if this bounds update is the result of
    // a Window::SetBoundsInternal call.
    if (!in_bounds_changed_)
        window_->SetBounds(rect);
    host_->WasResized();
    if (delegated_frame_host_)
        delegated_frame_host_->WasResized();
#if defined(OS_WIN)
    UpdateLegacyWin();

    if (mouse_locked_)
        UpdateMouseLockRegion();
#endif
}

#if defined(OS_WIN)
void RenderWidgetHostViewAura::UpdateLegacyWin()
{
    if (legacy_window_destroyed_ || !GetHostWindowHWND())
        return;

    if (!legacy_render_widget_host_HWND_) {
        legacy_render_widget_host_HWND_ = LegacyRenderWidgetHostHWND::Create(GetHostWindowHWND());
    }

    if (legacy_render_widget_host_HWND_) {
        legacy_render_widget_host_HWND_->set_host(this);
        legacy_render_widget_host_HWND_->UpdateParent(GetHostWindowHWND());
        legacy_render_widget_host_HWND_->SetBounds(
            window_->GetBoundsInRootWindow());
        // There are cases where the parent window is created, made visible and
        // the associated RenderWidget is also visible before the
        // LegacyRenderWidgetHostHWND instace is created. Ensure that it is shown
        // here.
        if (!host_->is_hidden())
            legacy_render_widget_host_HWND_->Show();
    }
}
#endif

void RenderWidgetHostViewAura::SchedulePaintIfNotInClip(
    const gfx::Rect& rect,
    const gfx::Rect& clip)
{
    if (!clip.IsEmpty()) {
        gfx::Rect to_paint = gfx::SubtractRects(rect, clip);
        if (!to_paint.IsEmpty())
            window_->SchedulePaintInRect(to_paint);
    } else {
        window_->SchedulePaintInRect(rect);
    }
}

void RenderWidgetHostViewAura::AddedToRootWindow()
{
    window_->GetHost()->AddObserver(this);
    UpdateScreenInfo(window_);

    aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(window_->GetRootWindow());
    if (cursor_client) {
        cursor_client->AddObserver(this);
        NotifyRendererOfCursorVisibilityState(cursor_client->IsCursorVisible());
    }
    if (HasFocus()) {
        ui::InputMethod* input_method = GetInputMethod();
        if (input_method)
            input_method->SetFocusedTextInputClient(this);
    }

#if defined(OS_WIN)
    UpdateLegacyWin();
#endif

    if (delegated_frame_host_)
        delegated_frame_host_->SetCompositor(window_->GetHost()->compositor());
}

void RenderWidgetHostViewAura::RemovingFromRootWindow()
{
    aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(window_->GetRootWindow());
    if (cursor_client)
        cursor_client->RemoveObserver(this);

    DetachFromInputMethod();

    window_->GetHost()->RemoveObserver(this);
    if (delegated_frame_host_)
        delegated_frame_host_->ResetCompositor();

#if defined(OS_WIN)
    // Update the legacy window's parent temporarily to the hidden window. It
    // will eventually get reparented to the right root.
    if (legacy_render_widget_host_HWND_)
        legacy_render_widget_host_HWND_->UpdateParent(ui::GetHiddenWindow());
#endif
}

void RenderWidgetHostViewAura::DetachFromInputMethod()
{
    ui::InputMethod* input_method = GetInputMethod();
    if (input_method)
        input_method->DetachTextInputClient(this);
}

void RenderWidgetHostViewAura::ForwardKeyboardEvent(
    const NativeWebKeyboardEvent& event)
{
    RenderWidgetHostImpl* target_host = host_;

    // If there are multiple widgets on the page (such as when there are
    // out-of-process iframes), pick the one that should process this event.
    if (host_->delegate())
        target_host = host_->delegate()->GetFocusedRenderWidgetHost(host_);
    if (!target_host)
        return;

#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
    ui::TextEditKeyBindingsDelegateAuraLinux* keybinding_delegate = ui::GetTextEditKeyBindingsDelegate();
    std::vector<ui::TextEditCommandAuraLinux> commands;
    if (!event.skip_in_browser && keybinding_delegate && event.os_event && keybinding_delegate->MatchEvent(*event.os_event, &commands)) {
        // Transform from ui/ types to content/ types.
        EditCommands edit_commands;
        for (std::vector<ui::TextEditCommandAuraLinux>::const_iterator it = commands.begin(); it != commands.end(); ++it) {
            edit_commands.push_back(EditCommand(it->GetCommandString(),
                it->argument()));
        }

        target_host->ForwardKeyboardEventWithCommands(event, &edit_commands);
        return;
    }
#endif

    target_host->ForwardKeyboardEvent(event);
}

void RenderWidgetHostViewAura::SelectionUpdated(
    bool is_editable,
    bool is_empty_text_form_control,
    const gfx::SelectionBound& start,
    const gfx::SelectionBound& end)
{
    selection_controller_->OnSelectionEditable(is_editable);
    selection_controller_->OnSelectionEmpty(is_empty_text_form_control);
    selection_controller_->OnSelectionBoundsChanged(start, end);
}

void RenderWidgetHostViewAura::CreateSelectionController()
{
    ui::TouchSelectionController::Config tsc_config;
    tsc_config.max_tap_duration = base::TimeDelta::FromMilliseconds(
        ui::GestureConfiguration::GetInstance()->long_press_time_in_ms());
    tsc_config.tap_slop = ui::GestureConfiguration::GetInstance()
                              ->max_touch_move_in_pixels_for_click();
    tsc_config.enable_longpress_drag_selection = false;
    selection_controller_.reset(new ui::TouchSelectionController(
        selection_controller_client_.get(), tsc_config));
}

void RenderWidgetHostViewAura::OnDidNavigateMainFrameToNewPage()
{
    ui::GestureRecognizer::Get()->CancelActiveTouches(window_);
}

void RenderWidgetHostViewAura::LockCompositingSurface()
{
    NOTIMPLEMENTED();
}

void RenderWidgetHostViewAura::UnlockCompositingSurface()
{
    NOTIMPLEMENTED();
}

cc::FrameSinkId RenderWidgetHostViewAura::GetFrameSinkId()
{
    return delegated_frame_host_ ? delegated_frame_host_->GetFrameSinkId()
                                 : cc::FrameSinkId();
}

cc::SurfaceId RenderWidgetHostViewAura::SurfaceIdForTesting() const
{
    return delegated_frame_host_ ? delegated_frame_host_->SurfaceIdForTesting()
                                 : cc::SurfaceId();
}

void RenderWidgetHostViewAura::OnUpdateTextInputStateCalled(
    TextInputManager* text_input_manager,
    RenderWidgetHostViewBase* updated_view,
    bool did_update_state)
{
    DCHECK_EQ(text_input_manager_, text_input_manager);

    if (!GetInputMethod())
        return;

    if (did_update_state)
        GetInputMethod()->OnTextInputTypeChanged(this);

    const TextInputState* state = text_input_manager_->GetTextInputState();
    if (state && state->show_ime_if_needed && GetInputMethod()->GetTextInputClient() == this) {
        GetInputMethod()->ShowImeIfNeeded();
    }

    if (state && state->type != ui::TEXT_INPUT_TYPE_NONE) {
        // Start monitoring the composition information if the focused node is
        // editable.
        RenderWidgetHostImpl* last_active_widget = text_input_manager_->GetActiveWidget();
        last_active_widget_routing_id_ = last_active_widget->GetRoutingID();
        last_active_widget_process_id_ = last_active_widget->GetProcess()->GetID();
        last_active_widget->Send(new InputMsg_RequestCompositionUpdate(
            last_active_widget->GetRoutingID(), false /* immediate request */,
            true /* monitor request */));
    } else {
        // Stop monitoring the composition information if the focused node is not
        // editable.
        RenderWidgetHostImpl* last_active_widget = RenderWidgetHostImpl::FromID(
            last_active_widget_process_id_, last_active_widget_routing_id_);
        if (last_active_widget) {
            last_active_widget->Send(new InputMsg_RequestCompositionUpdate(
                last_active_widget->GetRoutingID(), false /* immediate request */,
                false /* monitor request */));
        }
        last_active_widget_routing_id_ = MSG_ROUTING_NONE;
        last_active_widget_process_id_ = ChildProcessHost::kInvalidUniqueID;
    }
}

void RenderWidgetHostViewAura::OnImeCancelComposition(
    TextInputManager* text_input_manager,
    RenderWidgetHostViewBase* view)
{
    // |view| is not necessarily the one corresponding to
    // TextInputManager::GetActiveWidget() as RenderWidgetHostViewAura can call
    // this method to finish any ongoing composition in response to a mouse down
    // event.
    if (GetInputMethod())
        GetInputMethod()->CancelComposition(this);
    has_composition_text_ = false;
}

void RenderWidgetHostViewAura::OnSelectionBoundsChanged(
    TextInputManager* text_input_manager,
    RenderWidgetHostViewBase* updated_view)
{
    if (GetInputMethod())
        GetInputMethod()->OnCaretBoundsChanged(this);
}

void RenderWidgetHostViewAura::OnTextSelectionChanged(
    TextInputManager* text_input_manager,
    RenderWidgetHostViewBase* updated_view)
{
#if defined(USE_X11) && !defined(OS_CHROMEOS)
    if (!GetTextInputManager())
        return;

    // We obtain the TextSelection from focused RWH which is obtained from the
    // frame tree. BrowserPlugin-based guests' RWH is not part of the frame tree
    // and the focused RWH will be that of the embedder which is incorrect. In
    // this case we should use TextSelection for |this| since RWHV for guest
    // forwards text selection information to its platform view.
    RenderWidgetHostViewBase* focused_view = is_guest_view_hack_ ? this : GetFocusedWidget() ? GetFocusedWidget()->GetView() : nullptr;

    if (!focused_view)
        return;

    base::string16 selected_text;
    if (GetTextInputManager()
            ->GetTextSelection(focused_view)
            ->GetSelectedText(&selected_text)
        && selected_text.length()) {
        // Set the CLIPBOARD_TYPE_SELECTION to the ui::Clipboard.
        ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_SELECTION);
        clipboard_writer.WriteText(selected_text);
    }
#endif // defined(USE_X11) && !defined(OS_CHROMEOS)
}

void RenderWidgetHostViewAura::SetPopupChild(
    RenderWidgetHostViewAura* popup_child_host_view)
{
    popup_child_host_view_ = popup_child_host_view;
    event_handler_->SetPopupChild(
        popup_child_host_view,
        popup_child_host_view ? popup_child_host_view->event_handler() : nullptr);
}

} // namespace content
